package org.jha.rfid.motorola.fx9500;

import javax.swing.JFrame;

import com.mot.rfid.api3.ACCESS_OPERATION_CODE;
import com.mot.rfid.api3.ANTENNA_EVENT_TYPE;
import com.mot.rfid.api3.AccessFilter;
import com.mot.rfid.api3.AntennaInfo;
import com.mot.rfid.api3.DISCONNECTION_EVENT_TYPE;
import com.mot.rfid.api3.InvalidUsageException;
import com.mot.rfid.api3.LoginInfo;
import com.mot.rfid.api3.MEMORY_BANK;
import com.mot.rfid.api3.OperationFailureException;
import com.mot.rfid.api3.PostFilter;
import com.mot.rfid.api3.READER_TYPE;
import com.mot.rfid.api3.RFIDReader;
import com.mot.rfid.api3.ReaderManagement;
import com.mot.rfid.api3.RfidEventsListener;
import com.mot.rfid.api3.RfidReadEvents;
import com.mot.rfid.api3.RfidStatusEvents;
import com.mot.rfid.api3.START_TRIGGER_TYPE;
import com.mot.rfid.api3.STATUS_EVENT_TYPE;
import com.mot.rfid.api3.STOP_TRIGGER_TYPE;
import com.mot.rfid.api3.TAG_EVENT_REPORT_TRIGGER;
import com.mot.rfid.api3.TagAccess;
import com.mot.rfid.api3.TagData;
import com.mot.rfid.api3.TriggerInfo;

public class RFIDBaseDemo {
	private RFIDReader myReader = null;

	public static final String API_SUCCESS = "Function Succeeded";
	public static final String PARAM_ERROR = "Parameter Error";


	private boolean isAccessSequenceRunning = false;

	// To display tag read count

	// Access Filter
	private AccessFilter accessFilter = null;
	private boolean isAccessFilterSet = false;

	// Post Filter
	private PostFilter postFilter = null;
	private boolean isPostFilterSet = false;

	// Antenna Info
	private AntennaInfo antennaInfo = null;

	private TriggerInfo triggerInfo = null;
	private ReaderManagement rm = null;
	private LoginInfo loginInfo;

	private TagData[] myTags = null;

	public static void main(String[] args) {
		RFIDBaseDemo rfdb = new RFIDBaseDemo();
		rfdb.connectToReader("30.30.30.100", 0);
		rfdb.startRead();
		JFrame jf = new JFrame();
		jf.setVisible(true);
	}

	public RFIDReader getMyReader() {
		return myReader;
	}

	public RFIDBaseDemo() {

		// Create Reader Object
		myReader = new RFIDReader();

		// Hash table to hold the tag data
		isAccessSequenceRunning = false;

		// Create the Access Filter
		accessFilter = new AccessFilter();

		// create the post filter
		postFilter = new PostFilter();

		// Create Antenna Info
		antennaInfo = new AntennaInfo();

		// Create Pre-Filter

		triggerInfo = new TriggerInfo();

		triggerInfo.StartTrigger
				.setTriggerType(START_TRIGGER_TYPE.START_TRIGGER_TYPE_IMMEDIATE);
		triggerInfo.StopTrigger
				.setTriggerType(STOP_TRIGGER_TYPE.STOP_TRIGGER_TYPE_IMMEDIATE);

		triggerInfo.TagEventReportInfo
				.setReportNewTagEvent(TAG_EVENT_REPORT_TRIGGER.MODERATED);
		triggerInfo.TagEventReportInfo
				.setNewTagEventModeratedTimeoutMilliseconds((short) 500);

		triggerInfo.TagEventReportInfo
				.setReportTagInvisibleEvent(TAG_EVENT_REPORT_TRIGGER.MODERATED);
		triggerInfo.TagEventReportInfo
				.setTagInvisibleEventModeratedTimeoutMilliseconds((short) 500);

		triggerInfo.TagEventReportInfo
				.setReportTagBackToVisibilityEvent(TAG_EVENT_REPORT_TRIGGER.MODERATED);
		triggerInfo.TagEventReportInfo
				.setTagBackToVisibilityModeratedTimeoutMilliseconds((short) 500);

		triggerInfo.setTagReportTrigger(1);

		/* Reader Management Interface */
		rm = new ReaderManagement();
		loginInfo = new LoginInfo();
		loginInfo.setUserName("admin");

		if (System.getProperty("os.name").equals("Windows CE")) {
			String hostName = "127.0.0.1";
			// On Device, connect automatically to the reader
			connectToReader(hostName, 5084);

		}
	}

	public boolean connectToReader(String readerHostName, int readerPort) {
		boolean retVal = false;
		myReader.setHostName(readerHostName);
		loginInfo.setHostName(readerHostName);
		myReader.setPort(readerPort);
		// mainApp.setTitle("J_RFIDHostSample");
		// mainApp.setCursor(Cursor.WAIT_CURSOR);

		try {
			myReader.connect();

			myReader.Events.setInventoryStartEvent(true);
			myReader.Events.setInventoryStopEvent(true);
			myReader.Events.setAccessStartEvent(true);
			myReader.Events.setAccessStopEvent(true);
			myReader.Events.setAntennaEvent(true);
			myReader.Events.setGPIEvent(true);
			myReader.Events.setBufferFullEvent(true);
			myReader.Events.setBufferFullWarningEvent(true);
			myReader.Events.setReaderDisconnectEvent(true);
			myReader.Events.setReaderExceptionEvent(true);
			myReader.Events.setTagReadEvent(true);
			myReader.Events.setAttachTagDataWithReadEvent(false);

			myReader.Events.addEventsListener(new EventsHandler());
			retVal = true;
			// mainApp.setTitle("Connected to " + hostName);
			postStatusNotification(API_SUCCESS, null);
			// init GPI images on the main page
			// mainApp.initGPIportImages();

			// update Menu Items

		} catch (InvalidUsageException ex) {
			postStatusNotification(PARAM_ERROR, ex.getVendorMessage());
		} catch (OperationFailureException ex) {
			postStatusNotification(ex.getStatusDescription(),
					ex.getVendorMessage());
		}
		// mainApp.setCursor(Cursor.DEFAULT_CURSOR);
		return retVal;
	}

	public void disconnectReader() {
		try {
			myReader.disconnect();

			postStatusNotification(API_SUCCESS, null);

		} catch (InvalidUsageException ex) {
			postStatusNotification(PARAM_ERROR, ex.getVendorMessage());

		} catch (OperationFailureException ex) {
			postStatusNotification(ex.getStatusDescription(),
					ex.getVendorMessage());

		}
	}

	public void startRead() {
		PostFilter myPostFilter = null;
		AntennaInfo myAntennInfo = null;
		AccessFilter myAccessFilter = null;

		// Set the Antenna Info
		if (antennaInfo.getAntennaID() != null)
			myAntennInfo = antennaInfo;

		// set the post filter
		if (isPostFilterSet)
			myPostFilter = postFilter;

		// set the access filter
		if (isAccessFilterSet)
			myAccessFilter = accessFilter;

		try {

			// Access Sequence Operation - Read the specified Memory Bank

			int memoryBankSelected = 4;

			if (memoryBankSelected > 0) {
				TagAccess tagaccess = new TagAccess();
				MEMORY_BANK memoryBank = MEMORY_BANK.MEMORY_BANK_EPC;
				TagAccess.Sequence opSequence = tagaccess.new Sequence(
						tagaccess);
				TagAccess.Sequence.Operation op1 = opSequence.new Operation();
				op1.setAccessOperationCode(ACCESS_OPERATION_CODE.ACCESS_OPERATION_READ);

				switch (--memoryBankSelected) {
				case 0:
					memoryBank = MEMORY_BANK.MEMORY_BANK_RESERVED;
					break;
				case 1:
					memoryBank = MEMORY_BANK.MEMORY_BANK_EPC;
					break;
				case 2:
					memoryBank = MEMORY_BANK.MEMORY_BANK_TID;
					break;
				case 3:
					memoryBank = MEMORY_BANK.MEMORY_BANK_USER;
					break;
				}
				op1.ReadAccessParams.setMemoryBank(memoryBank);
				op1.ReadAccessParams.setByteCount(0);
				op1.ReadAccessParams.setByteOffset(0);
				op1.ReadAccessParams.setAccessPassword(0);
				myReader.Actions.TagAccess.OperationSequence.add(op1);
				myReader.Actions.TagAccess.OperationSequence.performSequence(
						myAccessFilter, triggerInfo, myAntennInfo);

				isAccessSequenceRunning = true;

			} else // Simple Inventory
			{
				myReader.Actions.Inventory.perform(myPostFilter, triggerInfo,
						myAntennInfo);
			}
			postStatusNotification(API_SUCCESS, null);

		} catch (InvalidUsageException ex) {
			postStatusNotification(PARAM_ERROR, ex.getVendorMessage());
		} catch (OperationFailureException ex) {
			postStatusNotification(ex.getStatusDescription(),
					ex.getVendorMessage());
		}

	}

	public void stopRead() {
		try {
			if (isAccessSequenceRunning) {
				myReader.Actions.TagAccess.OperationSequence.stopSequence();
				myReader.Actions.TagAccess.OperationSequence.deleteAll();
				isAccessSequenceRunning = false;
			} else {
				myReader.Actions.Inventory.stop();
			}
			postStatusNotification(API_SUCCESS, null);

		} catch (InvalidUsageException ex) {
			postStatusNotification(PARAM_ERROR, ex.getVendorMessage());
		} catch (OperationFailureException ex) {
			postStatusNotification(ex.getStatusDescription(),
					ex.getVendorMessage());
		}

	}

	public boolean logIn(READER_TYPE readerType) {
		boolean retVal = false;
		// mainApp.setCursor(Cursor.WAIT_CURSOR);

		try {
			rm.login(loginInfo, readerType);
			retVal = true;
			postStatusNotification(API_SUCCESS, null);

			// update Menu Items
			// mainApp.updateRMMenuItems(true);

		} catch (InvalidUsageException ex) {
			postStatusNotification(PARAM_ERROR, ex.getVendorMessage());
		} catch (OperationFailureException ex) {
			postStatusNotification(ex.getStatusDescription(),
					ex.getVendorMessage());
		}
		// mainApp.setCursor(Cursor.DEFAULT_CURSOR);
		return retVal;
	}

	public void logOut() {
		try {
			rm.logout();

			// update Menu Items
			// mainApp.updateRMMenuItems(false);
			postStatusNotification(API_SUCCESS, null);

		} catch (InvalidUsageException ex) {
			postStatusNotification(PARAM_ERROR, ex.getVendorMessage());

		} catch (OperationFailureException ex) {
			postStatusNotification(ex.getStatusDescription(),
					ex.getVendorMessage());

		}
	}

	public void postStatusNotification(String statusMsg, String vendorMsg) {
		String status;
		if (statusMsg == API_SUCCESS) {
			return;
		}

		if (vendorMsg != null && vendorMsg.length() > 0) {
			status = statusMsg + "[" + vendorMsg + "]";
		} else {
			status = statusMsg;
		}

		System.out.println(status);

	}

	public static byte[] hexStringToByteArray(String s) {
		int len = s.length();
		byte[] data = new byte[len / 2];
		for (int i = 0; i < len; i += 2) {
			data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character
					.digit(s.charAt(i + 1), 16));
		}
		return data;
	}

	public static String byteArrayToHexString(byte[] b) {
		StringBuffer sb = new StringBuffer(b.length * 2);
		for (int i = 0; i < b.length; i++) {
			int v = b[i] & 0xff;
			if (v < 16) {
				sb.append('0');
			}
			sb.append(Integer.toHexString(v));
		}
		return sb.toString().toUpperCase();
	}

	public MEMORY_BANK getMemoryBankEnum(int index) {
		MEMORY_BANK memBank = MEMORY_BANK.MEMORY_BANK_EPC;
		switch (index) {
		case 0:
			memBank = MEMORY_BANK.MEMORY_BANK_RESERVED;
			break;
		case 1:
			memBank = MEMORY_BANK.MEMORY_BANK_EPC;
			break;
		case 2:
			memBank = MEMORY_BANK.MEMORY_BANK_TID;
			break;
		case 3:
			memBank = MEMORY_BANK.MEMORY_BANK_USER;
			break;
		}
		return memBank;
	}

	// TODO
	public class EventsHandler implements RfidEventsListener {

		public EventsHandler() {

		}

		public void eventReadNotify(RfidReadEvents rre) {
			// displayTags displayTagsThread = new displayTags();
			// displayTagsThread.start();
			// System.out.println("Tag Read Notification");
			updateTags();
		}

		void updateTags() {
			myTags = myReader.Actions.getReadTags(100);
			if (myTags != null) {
				TagData lastTagData = myTags[myTags.length - 1];
				System.out.println(lastTagData.getAntennaID() + ":"
						+ lastTagData.getTagID());
			}

		}

		public void eventStatusNotify(RfidStatusEvents rse) {
			STATUS_EVENT_TYPE statusType = rse.StatusEventData
					.getStatusEventType();
			System.out.println(statusType);
			if (statusType == STATUS_EVENT_TYPE.INVENTORY_START_EVENT) {
			} else if (statusType == STATUS_EVENT_TYPE.INVENTORY_STOP_EVENT) {
			} else if (statusType == STATUS_EVENT_TYPE.ACCESS_START_EVENT) {
			} else if (statusType == STATUS_EVENT_TYPE.ACCESS_STOP_EVENT) {
			} else if (statusType == STATUS_EVENT_TYPE.ANTENNA_EVENT) {
				int antennaID = rse.StatusEventData.AntennaEventData
						.getAntennaID();

				String antennaEventValue = "";
				if (rse.StatusEventData.AntennaEventData.getAntennaEvent() == ANTENNA_EVENT_TYPE.ANTENNA_CONNECTED) {
					antennaEventValue = String.valueOf(antennaID)
							+ " Connected";
				} else if (rse.StatusEventData.AntennaEventData
						.getAntennaEvent() == ANTENNA_EVENT_TYPE.ANTENNA_DISCONNECTED) {
					antennaEventValue = String.valueOf(antennaID)
							+ " Disconnected";
				}
				System.out.println(antennaEventValue);
			} else if (statusType == STATUS_EVENT_TYPE.READER_EXCEPTION_EVENT) {
			} else if (statusType == STATUS_EVENT_TYPE.BUFFER_FULL_WARNING_EVENT) {
			} else if (statusType == STATUS_EVENT_TYPE.BUFFER_FULL_EVENT) {
			} else if (statusType == STATUS_EVENT_TYPE.DISCONNECTION_EVENT) {
				String disconnectionEventData = "";
				if (rse.StatusEventData.DisconnectionEventData
						.getDisconnectionEvent() == DISCONNECTION_EVENT_TYPE.READER_INITIATED_DISCONNECTION)
					disconnectionEventData = "Reader Initiated Disconnection";
				else if ((rse.StatusEventData.DisconnectionEventData
						.getDisconnectionEvent() == DISCONNECTION_EVENT_TYPE.CONNECTION_LOST))
					disconnectionEventData = "Connection Lost";
				else if ((rse.StatusEventData.DisconnectionEventData
						.getDisconnectionEvent() == DISCONNECTION_EVENT_TYPE.READER_EXCEPTION))
					disconnectionEventData = "Reader Exception";
				System.out.println(disconnectionEventData);

			} else if (statusType == STATUS_EVENT_TYPE.GPI_EVENT) {
				// mainApp.setGPIOnScreen(rse.StatusEventData.GPIEventData.getGPIPort(),
				// true, rse.StatusEventData.GPIEventData.getGPIEventState() ?
				// true : false);
			}

		}
	}
}
